#include "schedulewidget.h"
#include "ui_schedulewidget.h"
#include <QDate>
#include <QTableWidget>
#include <QComboBox>
#include <QHeaderView>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QSqlQuery>
#include <QFormLayout>
#include <QTimeEdit>
#include <QMessageBox>
#include <QDialogButtonBox>
#include <QSqlError>
#include <QTableWidgetItem>

/*
 * 计算自定义的周数编号
 * 此函数根据给定日期 `date` 计算其在该年中的周编号，假设每年的第一周
 * 是从 1 月 1 日所在的星期开始计算。
 * 计算逻辑：
 * 1. 获取该年的 1 月 1 日 `startOfYear`。
 * 2. 计算 1 月 1 日是星期几 `dayOfWeek`（范围 1-7）。
 * 3. 计算 `date` 距离 `startOfYear` 的天数 `days`。
 * 4. 使用公式 `(days + dayOfWeek - 1) / 7 + 1` 计算周编号。
 * @param date  需要计算周编号的日期
 * @return      该日期对应的周编号（从 1 开始）
 */
int customWeekNumber(const QDate& date) {
    QDate startOfYear(date.year(), 1, 1); // 获取该年的 1 月 1 日
    int dayOfWeek = startOfYear.dayOfWeek(); // 获取 1 月 1 日是星期几（1-7，周一到周日）
    int days = startOfYear.daysTo(date); // 计算 `date` 距离 1 月 1 日的天数
    int week = (days + dayOfWeek - 1) / 7 + 1; // 计算周编号
    return week;
}

/*
 * @brief ScheduleWidget 构造函数
 *
 * 该构造函数初始化课程表界面，包括：
 * 1. 调用 `setupUi()` 设置 UI 组件。
 * 2. 调用 `setupUI()` 进行额外的 UI 初始化（假设该函数存在）。
 * 3. 获取当前年份 `currentYear` 和当前周数 `currentWeek`。
 * 4. 设置 `yearComboBox` 和 `weekComboBox` 的默认值，显示当前年份和当前周数。
 * 5. 调用 `loadSchedule()` 加载当前周的课程表数据。
 * @param parent  父级 QWidget 指针（默认为 nullptr）。
 */
ScheduleWidget::ScheduleWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::ScheduleWidget) // 创建 UI 对象
{
    ui->setupUi(this); // 初始化 UI 组件
    setupUI(); // 额外 UI 设置（假设该函数存在）
    // 获取当前系统的年份和周数
    int currentYear = QDate::currentDate().year();
    int currentWeek = customWeekNumber(QDate::currentDate());
    // 设置下拉框默认显示当前年份
    yearComboBox->setCurrentText(QString::number(currentYear));
    // 设置下拉框默认显示当前周数
    weekComboBox->setCurrentText(QString("第 %1 周").arg(currentWeek));
    // 加载当前周的课程表数据
    loadSchedule();
}

/*
 * @brief ScheduleWidget 析构函数
 *
 * 释放 `ui` 资源，防止内存泄漏。
 */
ScheduleWidget::~ScheduleWidget()
{
    delete ui; // 释放 UI 资源
}


void ScheduleWidget::setupUI()
{
    // **主垂直布局（整个窗口的主布局）**
    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    // **水平布局（顶部的年份、周数选择）**
    QHBoxLayout* dateLayout = new QHBoxLayout();
    yearComboBox = new QComboBox(this);
    weekComboBox = new QComboBox(this);

    // 填充年份选择框
    int currentYear = QDate::currentDate().year();
    for (int year = 2020; year <= currentYear + 5; ++year)
        yearComboBox->addItem(QString::number(year), year);

    // 填充周选择框
    for (int week = 1; week <= 52; ++week)
        weekComboBox->addItem(QString("第 %1 周").arg(week), week);

    dateRangeLabel = new QLabel(this);

    // 添加周导航按钮，创建 "上一周" 和 "下一周" 按钮
    QPushButton* prevWeekBtn = new QPushButton("上一周", this);
    QPushButton* nextWeekBtn = new QPushButton("下一周", this);
    prevWeekBtn->setFixedWidth(200);
    nextWeekBtn->setFixedWidth(200);

    // **将控件添加到顶部的 `dateLayout`**
    dateLayout->addWidget(new QLabel("年份: ", this));
    dateLayout->addWidget(yearComboBox);
    dateLayout->addWidget(new QLabel("周数: ", this));
    dateLayout->addWidget(weekComboBox);
    dateLayout->addWidget(dateRangeLabel);
    dateLayout->addStretch();

    // **添加到主垂直布局**
    mainLayout->addLayout(dateLayout);

    // **创建课程表**
    tableWidget = new QTableWidget(this);
    tableWidget->setAlternatingRowColors(true);
    tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
    setupTable();

    // **创建底部按钮**
    addButton = new QPushButton("添加课程", this);
    deleteButton = new QPushButton("删除课程", this);
    addButton->setFixedWidth(200);
    deleteButton->setFixedWidth(200);

    connect(yearComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, &ScheduleWidget::loadSchedule);
    connect(weekComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, &ScheduleWidget::loadSchedule);
    connect(addButton, &QPushButton::clicked, this, &ScheduleWidget::addCourse);
    connect(deleteButton, &QPushButton::clicked, this, &ScheduleWidget::deleteCourse);
    connect(prevWeekBtn, &QPushButton::clicked, this, &ScheduleWidget::showPreviousWeek);
    connect(nextWeekBtn, &QPushButton::clicked, this, &ScheduleWidget::showNextWeek);
    connect(tableWidget, &QTableWidget::itemChanged, this, &ScheduleWidget::handleItemChanged);

    // **水平布局（底部按钮区域）**
    QHBoxLayout* buttonLayout = new QHBoxLayout();
    buttonLayout->addStretch(); // 左侧填充，使按钮居中
    buttonLayout->addWidget(prevWeekBtn);
    buttonLayout->addWidget(nextWeekBtn);
    buttonLayout->addWidget(addButton);
    buttonLayout->addWidget(deleteButton);
    buttonLayout->addStretch();  // 右侧填充，使按钮居中

    // **将表格和按钮布局添加到主垂直布局**
    mainLayout->addLayout(dateLayout);
    mainLayout->addWidget(tableWidget);
    mainLayout->addLayout(buttonLayout);

    // **设置窗口的主布局**
    setLayout(mainLayout);
}
void ScheduleWidget::setupTable() {
    // 定义一周的天数（列标题）
    QStringList days = { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" };
    // 定义时间段（行标题）
    times = { "上午1", "上午2", "下午1", "下午2", "晚上1", "晚上2" };
    // 设置表格的行数为天数的数量（7行）
    tableWidget->setRowCount(days.count());
    // 设置表格的列数为时间段的数量（6列）
    tableWidget->setColumnCount(times.count());
    // 获取当前选择的年份
    int year = yearComboBox->currentData().toInt();
    // 获取当前选择的周数
    int week = weekComboBox->currentData().toInt();
    // 计算当前选择的周的起始日期和结束日期
    QPair<QDate, QDate> weekRange = getWeekRange(year, week);
    QDate startDate = weekRange.first; // 获取该周的第一天
    // 用于存储表格的垂直表头（即每行的标签）
    QStringList verticalHeaders;
    // 遍历一周 7 天，将 "星期几 + 日期" 作为行标题
    for (int i = 0; i < days.count(); ++i) {
        QDate currentDate = startDate.addDays(i); // 计算当前日期
        verticalHeaders.append(QString("%1\n%2").arg(days[i]).arg(currentDate.toString("MM/dd")));
    }

    // 设置表格的垂直表头（行标题：星期几 + 日期）
    tableWidget->setVerticalHeaderLabels(verticalHeaders);
    // 设置表格的水平表头（列标题：时间段）
    tableWidget->setHorizontalHeaderLabels(times);
    // 让表格的列宽度自动平均分布
    tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    // 让表格的行高度自动平均分布
    tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    // 允许用户双击单元格或按键编辑内容
    tableWidget->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
}

void ScheduleWidget::loadSchedule()
{
    // 阻止 tableWidget 触发 itemChanged 信号，避免在加载数据时引发不必要的事件处理
    tableWidget->blockSignals(true);

    // 清空表格的内容，但不会影响表头
    tableWidget->clearContents();

    // 获取用户在下拉框中选择的年份和周数
    int year = yearComboBox->currentData().toInt();
    int week = weekComboBox->currentData().toInt();

    // 计算该周的起始日期和结束日期
    QPair<QDate, QDate> weekRange = getWeekRange(year, week);
    QDate startDate = weekRange.first; // 该周的星期一
    QDate endDate = weekRange.second;  // 该周的星期日

    // 在 UI 上显示本周的日期范围，例如 "2025-04-01到2025-04-07"
    dateRangeLabel->setText(startDate.toString("yyyy-MM-dd") + "到" + endDate.toString("yyyy-MM-dd"));

    // 创建一个 7 天 × 课程时间数 的二维数组，初始值为空字符串
    QVector<QVector<QString>> courses(7, QVector<QString>(times.count(), ""));

    // 查询数据库，获取当前周的课程信息
    QSqlQuery query;
    query.prepare("SELECT date, time, course_name FROM schedule WHERE date BETWEEN ? AND ?");
    query.addBindValue(startDate.toString("yyyy-MM-dd")); // 绑定查询的起始日期
    query.addBindValue(endDate.toString("yyyy-MM-dd"));   // 绑定查询的结束日期

    // 执行查询，并遍历结果集
    if (query.exec()) {
        while (query.next()) {
            QDate date = QDate::fromString(query.value(0).toString(), "yyyy-MM-dd"); // 课程日期
            QString time = query.value(1).toString();  // 课程时间
            int dayIndex = startDate.daysTo(date);     // 计算日期相对本周第一天的索引（0~6）
            int timeIndex = times.indexOf(time);       // 查找该时间在 times 列表中的索引

            // 确保日期和时间的索引有效
            if (dayIndex >= 0 && dayIndex < 7 && timeIndex != -1) {
                courses[dayIndex][timeIndex] = query.value(2).toString(); // 存储课程名称
            }
        }
    }

    // 遍历二维数组，将课程数据填充到 tableWidget 表格中
    for (int day = 0; day < 7; ++day) {
        for (int time = 0; time < times.count(); ++time) {
            // 创建一个新的表格项，并填充课程信息
            QTableWidgetItem* item = new QTableWidgetItem(courses[day][time]);
            item->setTextAlignment(Qt::AlignCenter); // 文本居中对齐
            tableWidget->setItem(day, time, item);  // 将 item 设置到表格中
        }
    }

    // 重新启用 tableWidget 的信号，允许用户交互
    tableWidget->blockSignals(false);
}



void ScheduleWidget::addCourse() {
    int dayIndex = tableWidget->currentRow();
    int timeIndex = tableWidget->currentColumn();
    if (dayIndex == -1 || timeIndex == -1) { // 验证选中位置有效性
        QMessageBox::warning(this, "错误", "请先选择一个时间段！");
        return;
    }
    // 检查时间段是否被占用
    if (!tableWidget->item(dayIndex, timeIndex)->text().isEmpty()) {
        QMessageBox::warning(this, "错误", "该时间段已被占用！");
        return;
    }

    QDialog dialog(this); // 创建自定义对话框
    dialog.setWindowTitle("添加课程");
    QFormLayout layout(&dialog);
    QComboBox nameCombo; // 学生姓名下拉框
    QSqlQuery nameQuery("SELECT name FROM studentInfo");

    while (nameQuery.next()) nameCombo.addItem(nameQuery.value(0).toString());
    // 时间映射表：列索引 -> 默认时间
    QMap<int, QTime> timePresets = { // 上午1到晚上2
        {0, QTime(9, 0)}, {1, QTime(11, 0)}, {2, QTime(14, 0)},
        {3, QTime(16, 0)}, {4, QTime(19, 0)}, {5, QTime(21, 0)}
    };

    QTimeEdit timeEdit; // 时间选择控件
    timeEdit.setDisplayFormat("HH:mm");
    timeEdit.setTime(timePresets.value(timeIndex)); // 设置列对应默认时间
    layout.addRow("学生姓名:", &nameCombo);
    layout.addRow("课程时间:", &timeEdit);
    QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    buttons.button(QDialogButtonBox::Ok)->setText("确定");
    buttons.button(QDialogButtonBox::Cancel)->setText("取消");
    layout.addRow(&buttons);

    connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
    connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
    if (dialog.exec() != QDialog::Accepted) return;

    // 生成组合字符串
    QString courseName = QString("%1, %2").arg(nameCombo.currentText())
                             .arg(timeEdit.time().toString("HH:mm"));

    // 获取日期信息
    int year = yearComboBox->currentData().toInt();
    int week = weekComboBox->currentData().toInt();
    QPair<QDate, QDate> weekRange = getWeekRange(year, week);
    QDate currentDate = weekRange.first.addDays(dayIndex);
    QString timeSlot = times[timeIndex]; // 原始时间段标识（如"上午1"）

    // 数据库操作
    QSqlQuery query;
    query.prepare("INSERT INTO schedule (date, time, course_name) VALUES (?, ?, ?)");
    query.addBindValue(currentDate.toString("yyyy-MM-dd"));
    query.addBindValue(timeSlot); // 存储原始时间段标识
    query.addBindValue(courseName); // 存储"姓名, HH:mm"格式
    if (!query.exec())
        QMessageBox::critical(this, "错误", "添加失败: " + query.lastError().text());
    else
        loadSchedule(); // 刷新显示
}




// 计算某一年某一周的起始日期和结束日期
QPair<QDate, QDate> ScheduleWidget::getWeekRange(int year, int week) {
    // 获取该年的1月1日
    QDate startDate(year, 1, 1);
    // 计算1月1日距离最近的星期一需要调整的天数（以确保每周从星期一开始）
    int daysToSubtract = startDate.dayOfWeek() - Qt::Monday;
    // 如果1月1日不是星期一，则往前调整到最近的星期一
    if (daysToSubtract > 0)
        startDate = startDate.addDays(-daysToSubtract);
    // 计算该年第 `week` 周的起始日期（从第1周开始，每周增加 7 天）
    QDate weekStart = startDate.addDays((week - 1) * 7);
    // 计算该周的结束日期（起始日期 + 6 天）
    QDate weekEnd = weekStart.addDays(6);
    // 返回该周的起始日期和结束日期
    return qMakePair(weekStart, weekEnd);
}


void ScheduleWidget::handleItemChanged(QTableWidgetItem* item)
{
    int day = item->row();
    int timeSlot = item->column();
    QString newCourse = item->text().trimmed();

    int year = yearComboBox->currentData().toInt();
    int week = weekComboBox->currentData().toInt();
    QPair<QDate, QDate> weekRange = getWeekRange(year, week);
    QDate date = weekRange.first.addDays(day);
    QString time = times[timeSlot];

    QSqlQuery query;
    if (newCourse.isEmpty()) {
        // 删除课程
        query.prepare("DELETE FROM schedule WHERE date = ? AND time = ?");
        query.addBindValue(date.toString("yyyy-MM-dd"));
        query.addBindValue(time);
    } else {
        // 使用REPLACE语句更新或插入
        query.prepare("INSERT OR REPLACE INTO schedule (date, time, course_name) VALUES (?, ?, ?)");
        query.addBindValue(date.toString("yyyy-MM-dd"));
        query.addBindValue(time);
        query.addBindValue(newCourse);
    }

    if (!query.exec()) {
        QMessageBox::critical(this, "错误", "操作失败: " + query.lastError().text());
        loadSchedule(); // 恢复数据
    } else {
        loadSchedule(); // 刷新显示数据
    }
}


void ScheduleWidget::deleteCourse()
{
    // 确认删除操作
    QMessageBox confirmBox(this);
    confirmBox.setWindowTitle("确认删除");
    confirmBox.setText("确定要删除该记录吗？");

    // 设置按钮为中文
    QPushButton* yesButton = confirmBox.addButton("确定", QMessageBox::YesRole);
    QPushButton* noButton = confirmBox.addButton("取消", QMessageBox::NoRole);

    // 设置默认按钮
    confirmBox.setDefaultButton(noButton);

    // 显示对话框并等待用户选择
    confirmBox.exec();

    if (confirmBox.clickedButton() == yesButton) {
        int dayIndex = tableWidget->currentRow();
        int timeIndex = tableWidget->currentColumn();

        if (dayIndex == -1 || timeIndex == -1) {
            QMessageBox::warning(this, "错误", "请先选择一个时间段！");
            return;
        }

        QTableWidgetItem* item = tableWidget->item(dayIndex, timeIndex);
        if (!item || item->text().isEmpty()) {
            QMessageBox::warning(this, "错误", "该时间段没有课程！");
            return;
        }

        int year = yearComboBox->currentData().toInt();
        int week = weekComboBox->currentData().toInt();
        QPair<QDate, QDate> weekRange = getWeekRange(year, week);
        QDate currentDate = weekRange.first.addDays(dayIndex);
        QString time = times[timeIndex];

        QSqlQuery query;
        query.prepare("DELETE FROM schedule WHERE date = ? AND time = ?");
        query.addBindValue(currentDate.toString("yyyy-MM-dd"));
        query.addBindValue(time);

        if (!query.exec()) {
            QMessageBox::critical(this, "错误", "删除失败：" + query.lastError().text());
        } else {
            loadSchedule(); // 刷新显示
        }
    }
}

void ScheduleWidget::showPreviousWeek()
{
    int currentWeek = weekComboBox->currentIndex();
    int currentYear = yearComboBox->currentIndex();

    if (currentWeek > 0) {
        weekComboBox->setCurrentIndex(currentWeek - 1);
    }
    else {
        if (yearComboBox->currentIndex() > 0) {
            yearComboBox->setCurrentIndex(currentYear - 1);
            // 跳转到上一年最后一周（第52周）
            weekComboBox->setCurrentIndex(51);
        }
    }
}


void ScheduleWidget::showNextWeek()
{
    int currentWeek = weekComboBox->currentIndex();
    int currentYear = yearComboBox->currentIndex();

    if (currentWeek < 51) {
        weekComboBox->setCurrentIndex(currentWeek + 1);
    }
    else {
        if (yearComboBox->currentIndex() < yearComboBox->count()-1) {
            yearComboBox->setCurrentIndex(currentYear + 1);
            weekComboBox->setCurrentIndex(0);
        }
    }
}
